﻿/** \file
* \$Rev: 187 $
* 
* \$Date: 2010-04-27 21:58:51 +0000 (Tue, 27 Apr 2010) $
*
* \$URL: http://chorus-twitter.googlecode.com/svn/trunk/src/net/Source.cs $
*/

using System;
using System.Collections.Generic;
using chorus.twitter;

namespace chorus.net
{
	/// <summary>
	/// The abstract parent for all source classes. These source classes
	/// represent a consistent way to fetch Twitter-related XML data with
	/// optional authorization via an account.
	/// </summary>
	/// <typeparam name="RootType">The type of object being fetched.</typeparam>
	public abstract class Source<RootType>
	{
		/// <summary>The map of query parameters to their values.</summary>
		protected List<AbstractQueryParameter> qparams = new List<AbstractQueryParameter>();
		/// <summary>The authorizing account.</summary>
		public Account Auth { get; set; }
		/// <summary>The URI for the source.</summary>
		public virtual UriBuilder Uri
		{
			get
			{
				UriBuilder builder = new UriBuilder("https", "api.twitter.com");
				string path = UriPath;
				if (UriType != "")
					path += "/" + UriType;
				builder.Path = path;

				string query = "";
				foreach (AbstractQueryParameter q in qparams)
				{
					if (q.IsSet)
					{
						if (query != "")
							query += "&";
						query += q.name + "=" + q.StringVal;
					}
				}
				builder.Query = query;
				return builder;
			}
		}
		/// <summary>The path part of the source URI.</summary>
		public virtual string UriPath { get { return "1"; } }
		/// <summary>The type part of the source URI.</summary>
		public virtual string UriType { get { return ""; } }

		/// <summary>Do a synchronous (blocking) fetch.</summary>
		/// <returns>The response object.</returns>
		public RootType FetchSync()
		{
			return GetNewParseState(null).HttpSyncResponse();
		}

		/// <summary>
		/// Fetch and deserialize synchronously (blocking). Keep trying until
		/// the request doesn't time out.
		/// </summary>
		/// <returns>The deserialized object.</returns>
		public RootType FetchSyncPersistent()
		{
			return GetNewParseState(null).HttpSyncResponsePersistent();
		}

		/// <summary>Do an asynchronous (non-blocking) fetch.</summary>
		/// <param name="deserialize">The deserialization callback function.</param>
		public void FetchAsync(Action<RootType> deserialize) { GetNewParseState(deserialize); }

		/// <summary>Get a new parse state appropriate for this source.</summary>
		/// <param name="deserialize">The deserialization callback.</param>
		/// <returns>The new parse state object.</returns>
		protected abstract ParseState<RootType> GetNewParseState(Action<RootType> deserialize);
	}

	/// <summary>
	/// A source whose response format is XML.
	/// </summary>
	/// <typeparam name="RootType">The type of the object being fetched.</typeparam>
	public class XmlSource<RootType> : Source<RootType>
	{
		/// <summary>Get a new parse state appropriate for this source.</summary>
		/// <param name="deserialize">The deserialization callback.</param>
		/// <returns>The new parse state object.</returns>
		protected override ParseState<RootType> GetNewParseState(Action<RootType> deserialize)
		{
			return new XmlParseState<RootType>(Uri, Auth, deserialize);
		}
	}

	/// <summary>
	/// A source whose response format is JSON.
	/// </summary>
	/// <typeparam name="RootType">The type of the object being fetched.</typeparam>
	public class JsonSource<RootType> : Source<RootType>
	{
		/// <summary>Get a new parse state appropriate for this source.</summary>
		/// <param name="deserialize">The deserialization callback.</param>
		/// <returns>The new parse state object.</returns>
		protected override ParseState<RootType> GetNewParseState(Action<RootType> deserialize)
		{
			return new JsonParseState<RootType>(Uri, Auth, deserialize);
		}
	}

	/// <summary>
	/// An interface to any source whose RootType implements
	/// MessageCollectionResponse. Basically, things that implement this
	/// interface fetch lists of messages.
	/// </summary>
	public interface IMessageSource
	{
		/// <summary>The authorizing account.</summary>
		Account Auth { get; set; }

		/// <summary>Do a synchronous (blocking) fetch.</summary>
		/// <returns>The response object.</returns>
		IMessageCollectionResponse FetchSync();

		/// <summary>Do an asynchronous (non-blocking) fetch.</summary>
		/// <param name="deserialize">The deserialization callback function.</param>
		void FetchAsync(Action<IMessageCollectionResponse> deserialize);
	}

	/// <summary>
	/// The base class for all sources that fetch a MessageCollectionResponse.
	/// </summary>
	/// <typeparam name="RootType">The type of object being fetched.</typeparam>
	public abstract class XmlMessageSource<RootType> :
		XmlSource<RootType>,
		IMessageSource
		where RootType : IMessageCollectionResponse
	{
		/// <summary>Do an asynchronous (non-blocking) fetch.</summary>
		/// <param name="deserialize">The deserialization callback function.</param>
		void IMessageSource.FetchAsync(Action<IMessageCollectionResponse> deserialize)
		{
			base.FetchAsync(delegate(RootType response) { deserialize(response); });
		}

		/// <summary>Do a synchronous (blocking) fetch.</summary>
		/// <returns>The response object.</returns>
		IMessageCollectionResponse IMessageSource.FetchSync() { return base.FetchSync(); }
	}

	/// <summary>
	/// The base class for all sources that fetch a MessageCollectionResponse.
	/// </summary>
	/// <typeparam name="RootType">The type of object being fetched.</typeparam>
	public abstract class JsonMessageSource<RootType> :
		JsonSource<RootType>,
		IMessageSource
		where RootType : IMessageCollectionResponse
	{
		/// <summary>Do an asynchronous (non-blocking) fetch.</summary>
		/// <param name="deserialize">The deserialization callback function.</param>
		void IMessageSource.FetchAsync(Action<IMessageCollectionResponse> deserialize)
		{
			base.FetchAsync(delegate(RootType response) { deserialize(response); });
		}

		/// <summary>Do a synchronous (blocking) fetch.</summary>
		/// <returns>The response object.</returns>
		IMessageCollectionResponse IMessageSource.FetchSync() { return base.FetchSync(); }
	}
}
